package com.coocaa.x.demo.servlets;

import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.drawable.Drawable;
import android.os.RemoteException;
import android.provider.Settings;
import android.util.Log;

import com.coocaa.x.demo.servlets.data.ApkData;
import com.coocaa.x.framework.app.CoocaaApplication;
import com.coocaa.x.framework.data.JObject;
import com.coocaa.x.framework.utils.Android;
import com.coocaa.x.framework.utils.LogUtils;
import com.coocaa.x.framework.utils.ShellUtils;
import com.coocaa.x.service.XServiceManager;
import com.coocaa.x.service.litedownloader.aidl.IDownloaderServiceListener;
import com.coocaa.x.service.litedownloader.data.DownloadError;
import com.coocaa.x.service.litedownloader.data.DownloadExtra;
import com.coocaa.x.service.litedownloader.data.DownloadTask;
import com.coocaa.x.service.litedownloader.data.ProcessInfo;
import com.coocaa.x.service.litepm.aidl.ILitePMInstallListener;
import com.coocaa.x.service.litepm.aidl.ILitePMUninstallListener;
import com.coocaa.x.service.litepm.data.AppInfo;
import com.coocaa.x.service.litepm.data.InstallParams;
import com.coocaa.x.service.litewebserver.webserver.LiteWebHttpd;
import com.coocaa.x.service.litewebserver.webserver.NanoHTTPD;
import com.coocaa.x.service.litewebserver.webserver.cache.ImageCache;
import com.coocaa.x.service.litewebserver.webserver.servlet.Servlet;
import com.skyworth.framework.skysdk.android.SdCardChecker;
import com.skyworth.logsdk.appstore.LogAPIForAppStore;
import com.skyworth.webSDK.webservice.tcappstore.AppStoreException;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.SocketTimeoutException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by lu on 15-9-10.
 */
public class AppServlet extends Servlet {
    private ServletInfo info = null;
    private Map<String, String> progressMap = new HashMap<String, String>();
    private Map<String,ApkData> apkDataMap = new HashMap<String,ApkData>();

    @Override
    protected void onCreate() {
        getSessionHandler().addHandler("/installedapps", installedapps);
        getSessionHandler().addHandler("/startapp", startapp);
        getSessionHandler().addHandler("/pushapk", pushapk);
        getSessionHandler().addHandler("/download", download);
        getSessionHandler().addHandler("/getprogress", getprogress);
        getSessionHandler().addHandler("/getallprogress", getallprogress);
        getSessionHandler().addHandler("/getapkinfo", getapkinfo);
        try {
            XServiceManager.getDownloaderService().setListener(downloaderServiceListener);
            XServiceManager.getLitePMService().addInstallListener(installListener);
            XServiceManager.getLitePMService().addUninstallListener(uninstallListener);
            XServiceManager.getDownloaderService().startAll();
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onDestroy() {

    }

    @Override
    protected NanoHTTPD.Response onServe(NanoHTTPD.IHTTPSession session) {
        return getSessionHandler().handle(session);
    }

    @Override
    public synchronized ServletInfo getServletInfo() {
        if (info == null) {
            info = new ServletInfo();
            info.vendorName = "superx";
            info.servletName = "app";
            info.versionCode = 1;
            info.versionName = "1.0.0";
        }
        return info;
    }

    @Override
    protected InputStream getResource(String uri) {
        return null;
    }

    private LiteWebHttpd.ServletHandler installedapps = new LiteWebHttpd.ServletHandler() {
        class AppInfo extends JObject {
            public String label, packageName, className, versionName;
            public String iconUrl;
        }

        class InstallAppsResponseMessage extends ResponseMessage {
            public List<AppInfo> data;
        }

        private List<AppInfo> getAppInfo(String pkgName, PackageManager pm) {
            List<AppInfo> infos = new ArrayList<AppInfo>();
            Intent intent = new Intent(Intent.ACTION_MAIN, null);
            intent.addCategory(Intent.CATEGORY_LAUNCHER);
            intent.setPackage(pkgName);
            List<ResolveInfo> resolveInfo = pm.queryIntentActivities(intent, PackageManager.GET_DISABLED_COMPONENTS);
            if (resolveInfo != null && resolveInfo.size() > 0) {
                for (ResolveInfo i : resolveInfo) {
                    AppInfo info = new AppInfo();
                    info.label = i.loadLabel(pm).toString();
                    info.packageName = pkgName;
                    info.className = i.activityInfo.name;
                    info.versionName = Android.getVersionName(CoocaaApplication.getContext(), pkgName);
//                    info.iconUrl = ImageCache.cacheImage(AppServlet.this, "http://img1.mydrivers.com/img/topimg/20150910/185513053.jpg", "http://img1.mydrivers.com/img/topimg/20150910/185513053.jpg");
                    info.iconUrl = ImageCache.getCacheImage(AppServlet.this, pkgName);
                    if (info.iconUrl == null)
                        info.iconUrl = ImageCache.cacheImageSync(AppServlet.this, pkgName, i.loadIcon(pm));
                    infos.add(info);
                }
            }
            return infos;
        }

        @Override
        public NanoHTTPD.Response serve(NanoHTTPD.IHTTPSession session) {
            InstallAppsResponseMessage msg = new InstallAppsResponseMessage();
            Context c = CoocaaApplication.getContext();
            PackageManager pm = c.getPackageManager();
            List<PackageInfo> packages = pm.getInstalledPackages(PackageManager.GET_ACTIVITIES);
            msg.data = new ArrayList<AppInfo>();
            for (int i = 0; i < packages.size(); i++) {
                PackageInfo packageInfo = packages.get(i);
                msg.data.addAll(getAppInfo(packageInfo.packageName, pm));
            }
            return newResponseMessage(msg);
        }
    };


    private LiteWebHttpd.ServletHandler startapp = new LiteWebHttpd.ServletHandler() {
        private static final String P_PACKAGENAME = "packageName";
        private static final String P_CLASSNAME = "className";

        @Override
        public NanoHTTPD.Response serve(NanoHTTPD.IHTTPSession session) {
            NanoHTTPD.Response r;
            Context c = CoocaaApplication.getContext();
            try {
                if (session.getParms().get(P_CLASSNAME) == null || session.getParms().get(P_CLASSNAME).equals("")){
                    Intent intent = c.getPackageManager().getLaunchIntentForPackage(session.getParms().get(P_PACKAGENAME));
                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    c.startActivity(intent);
                }else {
                    Intent intent = new Intent();
                    intent.setClassName(session.getParms().get(P_PACKAGENAME), session.getParms().get(P_CLASSNAME));
                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    c.startActivity(intent);
                }
                r = newResponseMessage(null);
            } catch (Exception e) {
                ResponseMessage msg = new ResponseMessage();
                msg.error_msg = e.getMessage();
                msg.error_code = -1;
                r = newResponseMessage(msg);
            }
            return r;
        }
    };


    private LiteWebHttpd.ServletHandler getapkinfo = new LiteWebHttpd.ServletHandler() {
        class PushApkResponseMessage extends ResponseMessage {
            public ApkData data;
        }
        @Override
        public NanoHTTPD.Response serve(NanoHTTPD.IHTTPSession session) {
            String file = session.getParms().get("filename");
            while (apkDataMap.get(file) == null){
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            PushApkResponseMessage msg = new PushApkResponseMessage();
            msg.data = apkDataMap.get(file);
            return newResponseMessage(msg);
        }
    };


    private LiteWebHttpd.ServletHandler pushapk = new LiteWebHttpd.ServletHandler() {
        class InstallException extends Exception {
            public InstallException(String detailMessage) {
                super(detailMessage);
            }
        }

        private static final String P_FILENAME = "filename";
        private static final int INSTALL_LOCATION_UNSPECIFIED = -1;
        private static final int INSTALL_LOCATION_AUTO = 0;
        private static final int INSTALL_LOCATION_INTERNAL_ONLY = 1;
        private static final int INSTALL_LOCATION_PREFER_EXTERNAL = 2;
        private static final String P_FILESIZE = "filesize";

        class PushApkResponseMessage extends ResponseMessage {
            public ApkData data;
        }

        @Override
        public NanoHTTPD.Response serve(NanoHTTPD.IHTTPSession session) {
            NanoHTTPD.Response r = newResponseMessage(null);
            String fileName =  session.getHeaders().get(P_FILENAME);
            String path = CoocaaApplication.getContext().getCacheDir().getAbsolutePath() + File.separator + fileName;
            int fileSize = Integer.valueOf(session.getHeaders().get(P_FILESIZE));
            File file = new File(path);
            try {
                InputStream is = session.getInputStream();
                byte[] buffer = new byte[4096];
                FileOutputStream fos = new FileOutputStream(file);
                int count;
                try{
                    while ((count = is.read(buffer)) != -1) {
                        fos.write(buffer, 0, count);
                        fileSize -= count;
                    }
                }catch (SocketTimeoutException e){
                    fos.close();
                    is.close();
                    if (fileSize == 0){
                        try {
                            LogUtils.i("push","begin install ");
                            ApkData data = install(path);
                            LogUtils.i("push","install success");
                            apkDataMap.put(fileName, data);
                            PushApkResponseMessage msg = new PushApkResponseMessage();
                            msg.data = data;
                            r = newResponseMessage(msg);
                        } catch (InstallException e1) {
                            e1.printStackTrace();
                            LogUtils.i("push", "install failed");
                            apkDataMap.put(fileName, new ApkData());
                            ResponseMessage msg = new ResponseMessage();
                            msg.error_code = -1;
                            msg.error_msg = e1.getMessage();
                            r = newResponseMessage(msg);
                        }
                    }

                }
            } catch (Exception e) {
                e.printStackTrace();
                ResponseMessage msg = new ResponseMessage();
                msg.error_code = -2;
                msg.error_msg = e.getMessage();
                r = newResponseMessage(msg);
            }
            if (file.exists())
                file.delete();
            return r;
        }

        public ApkData getApkInfo(String apkPath) {
            PackageManager pm = mContext.getPackageManager();
            PackageInfo pkgInfo = pm.getPackageArchiveInfo(apkPath, PackageManager.GET_ACTIVITIES);
            if (pkgInfo != null) {
                ApplicationInfo appInfo = pkgInfo.applicationInfo;
            /* 必须加这两句，不然下面icon获取是default icon而不是应用包的icon */
                appInfo.sourceDir = apkPath;
                appInfo.publicSourceDir = apkPath;
                String appName = pm.getApplicationLabel(appInfo).toString();// 得到应用名
                String packageName = appInfo.packageName; // 得到包名
                String versionName = pkgInfo.versionName; // 得到版本信息
                long size = new File(appInfo.publicSourceDir).length() / 1024;
                Drawable icon1 = pm.getApplicationIcon(appInfo);// 得到图标信息
                String url = ImageCache.getCacheImage(AppServlet.this, packageName);
                if (url == null)
                    url = ImageCache.cacheImageSync(AppServlet.this, packageName, icon1);
                return new ApkData(appName, versionName, packageName, url, size);
            }
            return null;
        }

        private ShellUtils.CommandResult exeInstallApk(String arg,String apkfile,String log){
            StringBuilder command = new StringBuilder().append("pm install -r " + arg).append(
                    apkfile);
            LogUtils.d("slient_install", log + " silent install  cmd:" + command);
            ShellUtils.CommandResult commandResult = ShellUtils
                    .execCommand(command.toString(), true, true);
            return commandResult;
        }

        private boolean judetmentResult(ShellUtils.CommandResult commandResult){
            if (commandResult.successMsg != null
                    && (commandResult.successMsg.contains("Success") || commandResult.successMsg
                    .contains("success"))) {
                return true;
            }
            return false;
        }

        private ApkData install(String apkfile) throws InstallException {
            try {
                LogUtils.d("slient_install", " chmod 777 " + apkfile);
                Runtime.getRuntime().exec("chmod 777 " + apkfile);
            } catch (Exception e) {
                e.printStackTrace();
                throw new InstallException("can not chmod apk file");
            }
            AppInfo appInfo = null;
            Android.ApkInfo apkInfo = Android.getAPKInfo(apkfile);
            if (apkInfo == null) {
            } else {
                int preferlocation = getInstallLocation(apkfile);
                LogUtils.d("install", "preferlocation:" + preferlocation);
                switch (preferlocation) {
                    case INSTALL_LOCATION_AUTO:
                        if (SdCardChecker.isSDCardAvaiable()) {
                            String arg = " -s ";
                            if (needInstallSystem(apkfile)) {
                                arg = "";
                            }
                            ShellUtils.CommandResult commandResult = exeInstallApk(arg,apkfile,"INSTALL_LOCATION_AUTO");
                            if (judetmentResult(commandResult)) {
                                return getApkInfo(apkfile);
                            }
                            if (arg.equals("")) {
                                throw new InstallException(commandResult.errorMsg);
                            }
                        }
                        ShellUtils.CommandResult commandResult0 = exeInstallApk("", apkfile, "INSTALL_LOCATION_AUTO");
                        if (judetmentResult(commandResult0)) {
                            return getApkInfo(apkfile);
                        } else {
                            throw new InstallException(commandResult0.errorMsg);
                        }
                    case INSTALL_LOCATION_INTERNAL_ONLY:
                        ShellUtils.CommandResult commandResult = exeInstallApk("", apkfile, "INSTALL_LOCATION_INTERNAL_ONLY");
                        if (judetmentResult(commandResult)) {
                            return getApkInfo(apkfile);
                        } else {
                            throw new InstallException(commandResult.errorMsg);
                        }
                    case INSTALL_LOCATION_PREFER_EXTERNAL:
                        if (SdCardChecker.isSDCardAvaiable()) {
                            String arg = " -s ";
                            if (needInstallSystem(apkfile)) {
                                throw new InstallException("system apk can not beinstalled in sdcard!");
                            }
                            ShellUtils.CommandResult commandResult1 = exeInstallApk(arg, apkfile, "INSTALL_LOCATION_PREFER_EXTERNAL");
                            if (judetmentResult(commandResult1)) {
                                return getApkInfo(apkfile);
                            } else {
                                throw new InstallException(commandResult1.errorMsg);
                            }
                        } else {
                            throw new InstallException("no sdcard!!");
                        }
                    default:
                        throw new InstallException("invalid install config!!");
                }
            }
            throw new InstallException("invalid install config!!");
        }

        private int getConfigInstallLocation() {
            int ret = Settings.Secure.getInt(mContext.getContentResolver(), "default_install_location", 0);
            LogUtils.d("install", "settings getInstallLocation:" + ret);
//        if(ret == 0)
//            return 2;    //应酷开系统需求，如果location为自动（0），则当成外部（2）来处理。
            return ret;
            // 0：自动
            // 1：内部
            // 2：外部
        }

        private int getInstallLocation(String apk) {
//        int pos = getApkPreferInstallLocation(apk);
//        LogUtils.d("install",apk + "apk getInstallLocation:" + pos);
//        if (pos <= 0)
            int pos = getConfigInstallLocation();
            LogUtils.d("install", apk + "settings getInstallLocation:" + pos);
            return pos;
        }

        private boolean needInstallSystem(String apkPath) {
            PackageInfo pkgInfo = mContext.getPackageManager().getPackageArchiveInfo(apkPath, PackageManager.GET_ACTIVITIES);
            LogUtils.d("install", "(pkgInfo != null):" + (pkgInfo != null));
            if (pkgInfo != null) {
                if (pkgInfo.sharedUserId != null && pkgInfo.sharedUserId.equals("android.uid.system")) {
                    LogUtils.d("install", apkPath + "is system uid !");
                    return true;
                }
                boolean isSystemApp = isSystemApp(pkgInfo.packageName);
                if (isSystemApp)
                    return true;
                return false;
            }
            return false;
        }

        private boolean isSystemApp(String pkg) {
            PackageManager pm = mContext.getPackageManager();
            try {
                ApplicationInfo info = pm.getApplicationInfo(pkg, PackageManager.GET_DISABLED_COMPONENTS);
                LogUtils.d("install", " sourceDir:" + info.sourceDir);
                if (info.sourceDir.startsWith("/system") || info.sourceDir.startsWith("system"))
                    return true;
                return false;
            } catch (PackageManager.NameNotFoundException e) {
                e.printStackTrace();
                return false;
            }
        }
    };

    private LiteWebHttpd.ServletHandler download = new LiteWebHttpd.ServletHandler() {
        private static final String PACKAGENAME = "packageName";
        private static final String TITLE = "title";
        private static final String POSTERURL = "posterUrl";
        private static final String ID = "id";

        @Override
        public NanoHTTPD.Response serve(NanoHTTPD.IHTTPSession session) {
            NanoHTTPD.Response r = newResponseMessage(null);
            Map<String, String> params = session.getParms();
            String url = getDownurl(params.get(ID), "");
            DownloadTask task1 = null;
            try {
                task1 = XServiceManager.getDownloaderService().getTask(url);
                if (task1 != null)
                    XServiceManager.getDownloaderService().start(task1);
            } catch (RemoteException e) {
                e.printStackTrace();
                ResponseMessage msg = new ResponseMessage();
                msg.error_code = -1;
                msg.error_msg = e.getMessage();
                r = newResponseMessage(msg);
            }
            if (url != null && task1 == null) {
                try {
                    DownloadTask task = new DownloadTask();
                    String title = URLDecoder.decode(params.get(TITLE), "UTF-8");
                    DownloadExtra extra = new DownloadExtra(params.get("id"), params.get(PACKAGENAME),
                            URLDecoder.decode(params.get(POSTERURL), "UTF-8"), title);
                    task = new DownloadTask(url);
                    task.title = title;
                    LogUtils.i("download", "title:" + task.title);
                    task.url = url;
                    task.filename = params.get(PACKAGENAME) + ".apk";
                    task.extra = extra.toString();
                    XServiceManager.getDownloaderService().add(task);
                    XServiceManager.getDownloaderService().start(task);
                    LogUtils.i("download", "add task success");
                    r = newResponseMessage(null);
                } catch (Exception e) {
                    ResponseMessage msg = new ResponseMessage();
                    msg.error_code = -1;
                    msg.error_msg = e.getMessage();
                    r = newResponseMessage(msg);
                    e.printStackTrace();
                }
            }
            return r;
        }
    };

    private LiteWebHttpd.ServletHandler getprogress = new LiteWebHttpd.ServletHandler() {

        class ProgressResponse extends ResponseMessage {
            public Progress progress = null;
        }

        class Progress {
            public String packageName = "";
            public String progress = "";
        }

        @Override
        public NanoHTTPD.Response serve(NanoHTTPD.IHTTPSession session) {

            Map<String, String> params = session.getParms();
            String pname = params.get("packageName");
            LogUtils.i("","pname:"+pname);
            synchronized (progressMap){
                if (progressMap.get(pname) != null) {
                    Progress progress = new Progress();
                    progress.packageName = pname;
                    progress.progress = progressMap.get(pname);
                    ProgressResponse response = new ProgressResponse();
                    response.progress = progress;
                    LogUtils.i("","pname:"+progress.progress);
                    return newResponseMessage(response);
                }
            }
            return newResponseMessage(null);
        }
    };


    private LiteWebHttpd.ServletHandler getallprogress = new LiteWebHttpd.ServletHandler() {

        class AllProgressResponse extends ResponseMessage {
            public List<Progress> data = null;
        }

        class Progress {
            public String packageName = "";
            public String progress = "";
        }

        @Override
        public NanoHTTPD.Response serve(NanoHTTPD.IHTTPSession session) {
            List<Progress> list = new ArrayList<Progress>();
            synchronized (progressMap){
                if (progressMap.size() > 0){
                    for (Map.Entry<String, String> entry : progressMap.entrySet()) {
                        Progress progress = new Progress();
                        progress.packageName = entry.getKey();
                        progress.progress = entry.getValue();
                        list.add(progress);
                        AllProgressResponse response = new AllProgressResponse();
                        response.data = list;
                        return newResponseMessage(response);
                    }
                }
            }
            return newResponseMessage(null);
        }
    };


    private static Map<String, String> urlMap = new HashMap<String, String>();

    private String getDownurl(String appid, String usercount) {
        try {
            LogUtils.i("download", "the appid is " + appid);
            String downurl = null;
            synchronized (urlMap) {
                downurl = urlMap.get(appid);
            }
            if (downurl == null) {
                downurl = CoocaaApplication.getCoocaaWebService().getAppStoreService().getDownAddress(
                        Integer.valueOf(appid), usercount);
                urlMap.put(appid, downurl);
            }
            LogUtils.i("download", "download url:" + downurl);
            return downurl;
        } catch (AppStoreException e) {
            LogAPIForAppStore.reportInterfaceError("获取应用下载地址接口",
                    Android.throwable2String(e));
            System.out.println("错误原因：" + e.getErrormsg());
        } catch (NumberFormatException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }


    private synchronized void addStatus(String key,String value){
        progressMap.put(key,value);
    }

    private synchronized  void removeStatus(String key){
        if (progressMap.containsKey(key))
            progressMap.remove(key);
    }


    IDownloaderServiceListener.Stub downloaderServiceListener = new IDownloaderServiceListener.Stub() {
        @Override
        public void onReady(DownloadTask task) throws RemoteException {

        }

        @Override
        public void onPrepare(DownloadTask task) throws RemoteException {
            DownloadExtra extra = JObject.parseJObject(task.extra, DownloadExtra.class);
            addStatus(extra.pkgname, "等待中");
            LogUtils.i("download", "task status 等待中");
        }

        @Override
        public void onStart(DownloadTask task) throws RemoteException {

        }

        @Override
        public void onStop(DownloadTask task) throws RemoteException {
            DownloadExtra extra = JObject.parseJObject(task.extra, DownloadExtra.class);
            addStatus(extra.pkgname, "暂停");
        }

        @Override
        public void onFinish(DownloadTask task) throws RemoteException {
            DownloadExtra extra = JObject.parseJObject(task.extra, DownloadExtra.class);
            addStatus(extra.pkgname, "安装中");
//            XServiceManager.getLitePMService().install(task.savepath, true,
//                    new InstallParams(InstallParams.INSTALL_FROM.COOCAA_MARKET));
            LogUtils.i("download", "task status 安装中");
        }

        @Override
        public void onDelete(DownloadTask task) throws RemoteException {
            final DownloadExtra extra = JObject.parseJObject(task.extra, DownloadExtra.class);
            if (XServiceManager.getLitePMService().isInstalled(extra.pkgname)) {
                addStatus(extra.pkgname, "打开");
            } else {
                addStatus(extra.pkgname, "安装到电视");
            }
        }

        @Override
        public void onProcessInfo(DownloadTask task, ProcessInfo info) throws RemoteException {
            DownloadExtra extra = JObject.parseJObject(task.extra, DownloadExtra.class);
            addStatus(extra.pkgname, String.valueOf(info.percent) + "%");
            LogUtils.i("download", "task status " + info.percent);
        }

        @Override
        public void onError(DownloadTask task, DownloadError error) throws RemoteException {
            XServiceManager.getDownloaderService().delete(task);
            DownloadExtra extra = JObject.parseJObject(task.extra, DownloadExtra.class);
            addStatus(extra.pkgname, "安装到电视");
            LogUtils.i("download", "task status 下载失败");
        }
    };

    ILitePMInstallListener.Stub installListener = new ILitePMInstallListener.Stub() {
        @Override
        public void onInstallStart(String apkfile, AppInfo pkgname, InstallParams params) throws RemoteException {

        }

        @Override
        public void onInstallEnd(String apkfile, AppInfo pkgname, int result, String extra, InstallParams params) throws RemoteException {
            LogUtils.i("download", "task status 打开" + pkgname + "; " + result + "; " + extra);
            if (result == 0) {
                addStatus(pkgname.pkgName, "打开");
            }else{
                addStatus(pkgname.pkgName, "安装到电视");
            }
        }
    };

    ILitePMUninstallListener.Stub uninstallListener = new ILitePMUninstallListener.Stub() {
        @Override
        public void onUninstallStart(AppInfo pkgname) throws RemoteException {

        }

        @Override
        public void onUninstallEnd(AppInfo pkgname, int result, String extra) throws RemoteException {
            if (progressMap.get(pkgname.pkgName) != null)
                removeStatus(pkgname.pkgName);
        }
    };
}
